import { App } from "../App";
import { Singleton } from "./Class";

export default class StringUtil extends Singleton<StringUtil>{
    // private property
    private _keyStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
    private _aesKey:string = '';
    private _aesIv:string = '';
    constructor(){
        super();
    }

    protected onInit(aesKey:string,aesIv:string){
        this._aesKey = aesKey;
        this._aesIv = aesIv;
    }

    // ASE编码
    public encode(data:string|Object) :string{
        //把生成的加密对象转换为字符串
        let _src:string = typeof data === 'object' ? JSON.stringify(data):data;
        if (App.Util.isEmpty) return '';
        if (this._aesIv.length < 16) 
            throw new Error('ASE:Key must be greater than or equal to 16 bits.');
            let _key = CryptoJS.enc.Utf8.parse(this._aesKey);
            let _iv = CryptoJS.enc.Utf8.parse(this._aesIv);
        let _result = CryptoJS.AES.decrypt(_src,_key, {iv:_iv,mode:CryptoJS.mode.CBC,padding:CryptoJS.pad.Pkcs7});
        return _result.toString(CryptoJS.enc.Utf8);
    }
    // ASE解码
    public decode(src:string) :string{
        if (App.Util.isEmpty(src)) return '';
        if (this._aesIv.length < 16) 
            throw new Error('ASE:Key must be greater than or equal to 16 bits.');
        let _key = CryptoJS.enc.Utf8.parse(this._aesKey);
        let _iv = CryptoJS.enc.Utf8.parse(this._aesIv);
        let _obj = CryptoJS.AES.encrypt(src,_key, {iv:_iv,mode:CryptoJS.mode.CBC,padding:CryptoJS.pad.Pkcs7});
        return CryptoJS.enc.Base64.stringify(_obj.ciphertext);
    }

    // public method for encoding
    public encode64(src:string|Object) {
        let _src:string = typeof src === 'object' ? JSON.stringify(src):src;
        let output = '';
        let chr1, chr2, chr3, enc1, enc2, enc3, enc4;
        let i = 0;
        _src = this.encodeUTF8(_src);
        while (i < _src.length) {
            chr1 = _src.charCodeAt(i++);
            chr2 = _src.charCodeAt(i++);
            chr3 = _src.charCodeAt(i++);
            enc1 = chr1 >> 2;
            enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
            enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
            enc4 = chr3 & 63;
            if (isNaN(chr2)) {
                enc3 = enc4 = 64;
            } else if (isNaN(chr3)) {
                enc4 = 64;
            }
            output = output +
                this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
                this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);
        }
        return output;
    }

    // public method for decoding
    public decode64(src:string):string {
        let output = '';
        let chr1, chr2, chr3;
        let enc1, enc2, enc3, enc4;
        let i = 0;
        src = src.replace(/[^A-Za-z0-9\+\/\=]/g, '');
        while (i < src.length) {
            enc1 = this._keyStr.indexOf(src.charAt(i++));
            enc2 = this._keyStr.indexOf(src.charAt(i++));
            enc3 = this._keyStr.indexOf(src.charAt(i++));
            enc4 = this._keyStr.indexOf(src.charAt(i++));
            chr1 = (enc1 << 2) | (enc2 >> 4);
            chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
            chr3 = ((enc3 & 3) << 6) | enc4;
            output = output + String.fromCharCode(chr1);
            if (enc3 !== 64) {
                output = output + String.fromCharCode(chr2);
            }
            if (enc4 !== 64) {
                output = output + String.fromCharCode(chr3);
            }
        }
        output = this.decodeUTF8(output);
        return output;
    }

    // private method for UTF-8 encoding
    public encodeUTF8(src:string):string {
        src = src.replace(/\r\n/g, '\n');
        let utftext = '';
        for (let n = 0; n < src.length; n++) {
            const c = src.charCodeAt(n);
            if (c < 128) {
                utftext += String.fromCharCode(c);
            } else if ((c > 127) && (c < 2048)) {
                utftext += String.fromCharCode((c >> 6) | 192);
                utftext += String.fromCharCode((c & 63) | 128);
            } else {
                utftext += String.fromCharCode((c >> 12) | 224);
                utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                utftext += String.fromCharCode((c & 63) | 128);
            }

        }
        return utftext;
    }

    // private method for UTF-8 decoding
    public decodeUTF8(utftext:string):string {
        let string = '';
        let i = 0;
        let c = 0, c2 = 0, c3 = 0;
        while (i < utftext.length) {
            c = utftext.charCodeAt(i);
            if (c < 128) {
                string += String.fromCharCode(c);
                i++;
            } else if ((c > 191) && (c < 224)) {
                c2 = utftext.charCodeAt(i + 1);
                string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
                i += 2;
            } else {
                c2 = utftext.charCodeAt(i + 1);
                c3 = utftext.charCodeAt(i + 2);
                string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
                i += 3;
            }
        }
        return string;
    }
}